package com.yk.system.controller;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.yk.api.system.dto.RegisterUserDTO;
import com.yk.api.system.dto.UpdateUserDTO;
import com.yk.api.system.dto.UserDTO;
import com.yk.api.system.dto.UserParamDTO;
import com.yk.api.system.vo.GatewayVo;
import com.yk.common.core.constant.NumberConstant;
import com.yk.common.core.domain.BasePageQuery;
import com.yk.common.core.domain.LoginUser;
import com.yk.common.core.domain.PageResult;
import com.yk.common.core.domain.Result;
import com.yk.common.core.enums.UserStatus;
import com.yk.common.core.exception.user.UserException;
import com.yk.common.core.utils.LoginHelper;
import com.yk.common.log.annotation.Log;
import com.yk.common.log.constant.LogConstants;
import com.yk.common.log.enums.BusinessType;
import com.yk.system.convert.UserConvert;
import com.yk.system.entity.Dept;
import com.yk.system.entity.Gateway;
import com.yk.system.entity.User;
import com.yk.system.entity.UserRole;
import com.yk.system.service.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * 用户管理 yk-system
 *
 * @author lmx
 * @date 2023/10/16 18:15
 */
@Api(tags = "用户管理")
@RestController
@RequiredArgsConstructor
@RequestMapping("/sys/user")
public class SysUserController {

    private final UserService userService;
    private final UserRoleService userRoleService;
    private final UserWxService userWxService;
    private final UserConvert userConvert;
    private final DeptService deptService;
    private final CustomerInfoService customerInfoService;
    private final GatewayService gatewayService;

    @ApiOperation("用户列表")
    @PostMapping("/page")
    public PageResult<UserDTO> page(@RequestBody BasePageQuery<UserDTO> pageParam) {
        IPage<UserDTO> page = userService.queryPage(pageParam);
        if (CollUtil.isNotEmpty(page.getRecords())) {
            page.getRecords().forEach(user -> {
                if (StrUtil.isNotEmpty(user.getPhone())) {
                    String companyName = customerInfoService.getCompanyNameByPhone(user.getPhone());
                    user.setCorporationName(companyName);
                }
                // 用户拥有的网关信息
                List<Gateway> list = gatewayService.getByUserId(user.getId());
                if (CollUtil.isEmpty(list)){
                    list = CollUtil.newArrayList();
                }
                List<GatewayVo> gatewayList = list.stream().map(it -> {
                    GatewayVo vo = new GatewayVo();
                    vo.setName(it.getName());
                    vo.setNumber(it.getNumber());
                    return vo;
                }).collect(Collectors.toList());
                user.setGatewayList(gatewayList);
            });
        }
        return PageResult.success(page.getRecords(), page.getTotal());
    }

    @Log(title = "内部账户管理", businessType = BusinessType.INSERT)
    @ApiOperation("内部账户新增用户")
    @PostMapping("/addAdmin")
    public Result<Void> addAdmin(@Validated @RequestBody User user) {
        if (!userService.checkUserNameUnique(user)) {
            return Result.fail("新增用户：" + user.getUserName() + "'失败，登录账号已存在");
        } else if (!userService.checkPhoneUnique(user)) {
            return Result.fail("新增用户：" + user.getUserName() + "'失败，手机号码已存在");
        }
        if (StrUtil.isNotEmpty(user.getPassword())) {
            user.setPassword(BCrypt.hashpw(user.getPassword()));
        }
        userService.save(user);
        saveUserRole(user);
        return Result.ok2Log(LogConstants.ADD + user.getUserName());
    }

    @Log(title = "内部账户管理", businessType = BusinessType.UPDATE)
    @ApiOperation("内部账户分配管理员")
    @PostMapping("/updateAdmin")
    public Result<Void> updateAdmin(@Validated @RequestBody UserDTO userDTO) {
        String phone = userDTO.getPhone();
        LambdaQueryWrapper<User> lambda = new LambdaQueryWrapper<>();
        lambda.eq(User::getPhone, phone);
        User user = userService.getOne(lambda);
        if (Objects.isNull(user)) {
            return Result.fail("用户不存在");
        }
        UserRole userRole = userRoleService.getOne(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, user.getId()));
        if (Objects.nonNull(userRole)) {
            return Result.fail("该用户已是管理角色");
        }
        saveUserRole(user);
        return Result.ok2Log("内部账户分配管理员" + user.getUserName());
    }

    @Log(title = "内部账户管理", businessType = BusinessType.UPDATE)
    @ApiOperation("内部账户移除管理员")
    @PostMapping("/delAdmin")
    public Result<Void> delAdmin(@RequestBody UserDTO userDTO) {
        User user = userService.getById(userDTO.getId());
        delUserRole(userDTO.getId());
        return Result.ok2Log("内部账户移除管理员" + user.getUserName());
    }

    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @ApiOperation("修改当前用户")
    @PostMapping("/editLoginUser")
    public Result<Void> editLoginUser(@Validated @RequestBody User user) {
        Long userId = LoginHelper.getLoginUserId();
        user.setId(userId);
        user.setPassword(null);
        user.setUserName(null);
        user.setPhone(null);
        userService.updateById(user);
        return Result.ok2Log(LogConstants.UPDATE + "用户信息");
    }

    @ApiOperation("获取当前用户")
    @GetMapping("/getLoginUser")
    public Result<UserDTO> getLoginUser() {
        User user = userService.getById(LoginHelper.getLoginUserId());
        if (ObjectUtil.isNull(user)) {
            throw new UserException("获取用户信息失败");
        }
        return Result.data(userConvert.entity2Dto(user));
    }

    @Log(title = "用户管理", businessType = BusinessType.INSERT)
    @ApiOperation("新增用户")
    @PostMapping("/add")
    public Result<Void> add(@Validated @RequestBody User user) {
        if (!userService.checkUserNameUnique(user)) {
            return Result.fail("新增用户：" + user.getUserName() + "'失败，登录账号已存在");
        } else if (!userService.checkPhoneUnique(user)) {
            return Result.fail("新增用户：" + user.getUserName() + "'失败，手机号码已存在");
        }
        if (StrUtil.isNotEmpty(user.getPassword())) {
            user.setPassword(BCrypt.hashpw(user.getPassword()));
        }
        userService.save(user);
        return Result.ok2Log(LogConstants.ADD + user.getUserName());
    }

    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @ApiOperation("修改用户")
    @PostMapping("/edit")
    public Result<Void> edit(@Validated @RequestBody User user) {
        user.setPassword(null);
        user.setUserName(null);
        user.setPhone(null);
        userService.checkUserAllowed(user);
        userService.updateById(user);
        return Result.ok();
    }

    @Log(title = "用户管理", businessType = BusinessType.DELETE)
    @ApiOperation("修改用户状态")
    @PostMapping("/updateStatus")
    public Result<Void> updateStatus(@RequestBody UserDTO userDTO) {
        Long id = userDTO.getId();
        Assert.notNull(id, "用户ID不能为空");
        String status = userDTO.getStatus();
        Assert.notEmpty(status, "帐号状态不能为空");
        User user = userService.getById(id);
        String message = "禁用";
        if (NumberConstant.ONE_STR.equals(status)) {
            message = "启用";
        }
        user.setStatus(status);
        userService.updateById(user);
        return Result.ok2Log(message + user.getUserName());
    }

    @Log(title = "用户管理", businessType = BusinessType.DELETE)
    @ApiOperation("删除用户")
    @PostMapping("/delUser")
    public Result<Void> remove(@RequestBody UserParamDTO userParamDTO) {
        List<Long> userIds = userParamDTO.getUserIds();
        if (CollUtil.isEmpty(userIds)) {
            return Result.fail("没有要删除的用户");
        }
        if (userIds.contains(LoginHelper.getLoginUserId())) {
            return Result.fail("当前用户不能删除");
        }
        userService.deleteUserByIds(userIds);
        return Result.ok();
    }

    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @ApiOperation("重置密码")
    @PostMapping("/resetPwd")
    public Result<Void> resetPwd(@RequestBody User user) {
        userService.checkUserAllowed(user);
        user.setPassword(BCrypt.hashpw(user.getPassword()));
        userService.updateById(user);
        return Result.ok();
    }

    @ApiOperation("获取部门树列表")
    @GetMapping("/deptTree")
    public Result<List<Tree<Long>>> deptTree(@RequestBody Dept dept) {
        return Result.ok(deptService.selectDeptTreeList(dept));
    }

    @ApiOperation("通过用户名查询用户信息")
    @GetMapping("/info")
    public Result<LoginUser> getUserInfo(String username) {
        LambdaQueryWrapper<User> lambda = new LambdaQueryWrapper<>();
        lambda.select(User::getId, User::getUserName, User::getStatus, User::getPassword, User::getPhone, User::getNickName);
        lambda.eq(User::getUserName, username);
        lambda.or();
        lambda.eq(User::getPhone, username);
        User user = userService.getOne(lambda);
        if (ObjectUtil.isNull(user)) {
            throw new UserException("用户不存在");
        }
        if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            throw new UserException("用户已停用");
        }
        return Result.data(buildLoginUser(user));
    }

    @ApiOperation("通过用户名查询用户信息")
    @GetMapping("/infoById")
    public Result<LoginUser> getUserInfoById(Long userId) {
        User user = userService.getById(userId);
        if (ObjectUtil.isNull(user)) {
            throw new UserException("用户不存在");
        }
        if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            throw new UserException("用户已停用");
        }
        return Result.data(buildLoginUser(user));
    }

    @ApiOperation("通过手机号查询用户信息")
    @GetMapping("/infoByPhone")
    public Result<LoginUser> getUserInfoByPhone(String phone) {
        LambdaQueryWrapper<User> lambda = new LambdaQueryWrapper<>();
        lambda.select(User::getId, User::getUserName, User::getStatus, User::getPassword, User::getPhone, User::getNickName);
        lambda.eq(User::getPhone, phone);
        User user = userService.getOne(lambda);
        if (ObjectUtil.isNull(user)) {
            return Result.fail("用户不存在");
        }
        if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            return Result.fail("用户已停用");
        }
        return Result.data(buildLoginUser(user));
    }

    @ApiOperation("通过openid查询用户信息")
    @GetMapping("/infoByOpenId")
    public Result<LoginUser> getUserInfoByOpenId(String openId) {
        UserDTO user = userWxService.selectUserByOpenId(openId);
        if (Objects.isNull(user)) {
            return Result.ok();
        }
        if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            return Result.fail("用户已停用");
        }
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(user.getId());
        loginUser.setUsername(user.getUserName());
        loginUser.setPhone(user.getPhone());
        loginUser.setNickname(user.getNickName());
        return Result.data(loginUser);
    }

    @ApiOperation("注册用户信息")
    @PostMapping("/register")
    public Result<LoginUser> registerUserInfo(@RequestBody RegisterUserDTO dto) {
        User user = userConvert.dto2EntityByRegister(dto);
        if (!userService.checkUserNameUnique(user)) {
            throw new UserException("用户名已存在");
        }
        if (!userService.checkPhoneUnique(user)) {
            throw new UserException("手机号已存在");
        }
        user.setId(IdWorker.getId());
        if (CharSequenceUtil.isEmpty(user.getNickName())) {
            user.setNickName(user.getUserName());
        }
        userService.save(user);
        LoginUser userInfo = new LoginUser();
        userInfo.setUsername(user.getUserName());
        userInfo.setUserId(user.getId());
        userInfo.setPhone(user.getPhone());
        userInfo.setNickname(user.getNickName());
        return Result.data(userInfo);
    }

    @ApiOperation("密码修改")
    @PostMapping("/updatePassword")
    public Result<Boolean> updatePassword(@RequestBody UpdateUserDTO dto) {
        // 比对手机号是否属于当前用户人
        LoginUser loginUser = LoginHelper.getLoginUser();
        String myPhone = loginUser.getPhone();
        if (!myPhone.equals(dto.getPhone())) {
            throw new UserException("手机号不属于当前用户");
        }
        String phone = dto.getPhone();
        User user = userService.checkPhoneByUser(phone);
        user.setPassword(BCrypt.hashpw(dto.getPassword()));
        userService.updateById(user);
        return Result.ok();
    }

    @ApiOperation("忘记密码修改")
    @PostMapping("/forgotAndUpdatePassword")
    public Result<Boolean> forgotAndUpdatePassword(@RequestBody UpdateUserDTO dto) {
        String phone = dto.getPhone();
        User user = userService.checkPhoneByUser(phone);
        user.setPassword(BCrypt.hashpw(dto.getPassword()));
        userService.updateById(user);
        return Result.ok();
    }

    @ApiOperation("手机号修改")
    @PostMapping("/updatePhone")
    public Result<Boolean> updatePhone(@RequestBody UpdateUserDTO dto) {
        String oldPhone = dto.getOldPhone();
        String phone = dto.getPhone();
        User user = userService.checkPhoneByUser(oldPhone);
        user.setPhone(phone);
        if (!userService.checkPhoneUnique(user)) {
            throw new UserException("手机号已存在");
        }
        userService.updateById(user);
        LoginUser loginUser = buildLoginUser(user);
        LoginHelper.setLoginUser(loginUser);
        StpUtil.getTokenSessionTimeout();
        return Result.ok();
    }

    @ApiOperation(value = "系统引导", notes = "true-已执行")
    @GetMapping("/steer/{userId}")
    public Result<Boolean> steer(@PathVariable Long userId) {
        User user = userService.getById(userId);
        Assert.notNull(user, "用户不存在");
        if (NumberConstant.ZERO_STR.equals(user.getSteer())) {
            user.setSteer(NumberConstant.TWO_STR);
            userService.updateById(user);
            return Result.data(Boolean.FALSE);
        }
        return Result.data(Boolean.TRUE);
    }

    /**
     * 构建登录用户
     */
    private LoginUser buildLoginUser(User user) {
        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(user.getId());
        loginUser.setPassword(user.getPassword());
        loginUser.setUsername(user.getUserName());
        loginUser.setPhone(user.getPhone());
        loginUser.setNickname(user.getNickName());
        return loginUser;
    }

    /**
     * 保存用户角色
     */
    private void saveUserRole(User user) {
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(2L);
        userRoleService.save(userRole);
    }

    /**
     * 删除用户角色
     */
    private void delUserRole(Long userId) {
        userRoleService.remove(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, userId));
    }
}
